/*
 * QE3e Qt Quick 3D Engine.
 * Copyright (C) 2010 Joris Vaillant and Mathieu Pujol 
 * <joris.vaillant@gmail.com>  <mathieu.pujol87@gmail.com>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */


#include "TextureManager.h"

//Qt
#include <QDebug>
#include <QImage>

namespace qe3e
{

  TextureManager * TextureManager::mInstance = NULL;

  TextureManager * TextureManager::getInstance()
  {
    if(! mInstance)
    {
      mInstance = new TextureManager();
    }
    return mInstance;
  }

  void TextureManager::destroy()
  {
    delete mInstance;
    mInstance=NULL;
  }

  Texture TextureManager::getTexture2D(const QString & fileName,
                                       Texture::TextureType type,
                                       bool forceReloadAndMemorySeparation)
  {
    GLuint texId=0;

    mMutex.lock();
    if(mFileHash.contains(fileName) && !forceReloadAndMemorySeparation)
    {
      texId=mFileHash.value(fileName);
    }
    else
    {
      //load file and generate a new texid
      glGenTextures(1,&texId);
      if(!texId)
      {
        qWarning() << "Unable to create texture for file : " + fileName;
      }
      else
      {
        loadTexture2D(fileName,texId);

        mFileHash.insert(fileName,texId);
        mUseCpt.insert(texId,0);
      }
    }
    mMutex.unlock();

    return Texture(texId,type);
  }

  void TextureManager::incUseCptr(GLuint texId)
  {
    if(!texId)
    {
      return;
    }
    mMutex.lock();
    //qDebug()<<"inc"<<texId;
    int cpt=0;
    if(mUseCpt.contains(texId))
    {
      cpt = mUseCpt.take(texId);
    }
    ++cpt;
    mUseCpt.insert(texId,cpt);
    mMutex.unlock();
  }

  void TextureManager::decUseCptr(GLuint texId)
  {
    if(!texId)
    {
      return;
    }
    //qDebug()<<"dec"<<texId;
    mMutex.lock();
    if(mUseCpt.contains(texId))
    {
      int cpt = mUseCpt.take(texId);
      --cpt;
      if(cpt>0)
      {
        mUseCpt.insert(texId,cpt);
      }
      else
      {
        //destruction de la texture
        destroyTexture(texId);
      }
    }
    else
    {
      Q_ASSERT(mUseCpt.contains(texId));
      qWarning()<<"The manager does not contains this texture id";
    }
    mMutex.unlock();
  }


  TextureManager::TextureManager()
  {

  }

  TextureManager::~TextureManager()
  {
    clear();
  }

  void TextureManager::clear()
  {
    QList<GLuint> keys = mUseCpt.keys();
    foreach(GLuint key, keys)
    {
      destroyTexture(key);
    }
  }

  void TextureManager::destroyTexture(GLuint texId)
  {
    //qDebug()<<"destroy"<<texId;
    glDeleteTextures(1,&texId);
    mFileHash.remove(mFileHash.key(texId));
  }

  void TextureManager::loadTexture2D(const QString & fileName, GLuint texId)
  {
    QImage texture(fileName);

    if(!texture.isNull())
    {
      texture = texture.mirrored(false, true); // inverse l'axe y
      texture = texture.rgbSwapped();

      GLenum format = GL_RGB;

      switch(texture.depth())
      {
      case 24:
        format = GL_RGB;
        break;
      case 32:
        format = GL_RGBA;
        break;
      default:
        qWarning() << "This image depth (" + QString::number(texture.depth())
            + ") was not allowed : " + fileName;
        return;
      }

      glBindTexture(GL_TEXTURE_2D, texId);
      gluBuild2DMipmaps(GL_TEXTURE_2D, format, texture.width(), texture.height(), format, GL_UNSIGNED_BYTE, texture.bits());

      glBindTexture(GL_TEXTURE_2D, 0);
    }
    else
    {
      qWarning()<<"This file does not exist ! " + fileName;
    }
  }
}
